using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Entities.ActorClasses;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Base;
using System.IO;
using System.Xml.Serialization;
namespace Entities
{
    public class EntityController : DrawableGameComponent, IEntityController
    {
        private List<IActor> _actors = new List<IActor>();
        private Dictionary<string, ActorInfo> actorTypes = new Dictionary<string, ActorInfo>();
        private IActor highlightedActor = null;
        private ProjectileController projectiles;

        public IActor HighlightedActor
        {
            get { return highlightedActor; }
        }
        public Dictionary<string, ActorInfo> ActorTypes
        {
            get { return actorTypes; }
            set { actorTypes = value; }
        }
        private List<IActor> _selectedActors = new List<IActor>();
        private Matrix _reflectionViewMatrix;

        public Matrix ReflectionViewMatrix
        {
            get { return _reflectionViewMatrix; }
            set { _reflectionViewMatrix = value; }
        }

        public List<IActor> SelectedActors
        {
            get { return _selectedActors; }
        }
        public List<IActor> Actors
        {
            get { return _actors; }
        }

        public EntityController(Game game)
            : base(game)
        {
            IParticleController particles = (IParticleController)base.Game.Services.GetService(typeof(IParticleController));
            projectiles = new ProjectileController(particles);
        }

        public IActor CreateActor(string unitType)
        {
            IActor newActor = null;
            ActorInfo newInfo = ActorTypes[unitType];
            switch (newInfo.Type)
            {
                case UnitType.Flying:
                    newActor = new Ship(base.Game, newInfo, this);
                    break;
                case UnitType.Wheeled:
                    newActor = new Tank(base.Game, newInfo, this);
                    break;
                default:
                    break;
            }
            Actors.Add(newActor);
            return newActor;
        }
        public override void Initialize()
        {
            string[] entitiesFiles = Directory.GetFiles("Content/Entities");
            foreach (string entityFile in entitiesFiles)
            {
                ActorInfo newActorType = Deserialise(File.ReadAllText(entityFile));
                actorTypes.Add(newActorType.Name, newActorType);
            }
            base.Initialize();
        }
        public void UnitDestroyed(IActor unit)
        {
            IParticleController particles = (IParticleController)base.Game.Services.GetService(typeof(IParticleController));
            particles.CreateExplosion(unit.AdjustedPosition);
            particles.CreateFire(unit.AdjustedPosition, 1, 750);
            _actors.Remove(unit);
            _selectedActors.Remove(unit);
            if (highlightedActor == unit)
            {
                highlightedActor = null;
            }
        }

        private ActorInfo Deserialise(string xml)
        {
            XmlSerializer serialiser = new XmlSerializer(typeof(ActorInfo));
            MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
            stream.Seek(0, SeekOrigin.Begin);
            return (ActorInfo)serialiser.Deserialize(stream);
        }

        public override void Update(GameTime gameTime)
        {

            ICameraService camera = (ICameraService)base.Game.Services.GetService(typeof(ICameraService));
            ITerrainController terrain = (ITerrainController)base.Game.Services.GetService(typeof(ITerrainController));
            IDrawing2DManager drawing = (IDrawing2DManager)base.Game.Services.GetService(typeof(IDrawing2DManager));
            IDrawing3DManager drawing3D = (IDrawing3DManager)base.Game.Services.GetService(typeof(IDrawing3DManager));

            projectiles.Update(gameTime, drawing3D);

            //GameInformation
            highlightedActor = null;
            foreach (IActor currentActor in Actors)
            {
                if (currentActor.Update(gameTime, base.GraphicsDevice, camera, terrain, drawing, projectiles))
                {
                    highlightedActor = currentActor;
                }
            }
        }

        public override void Draw(GameTime gameTime)
        {
            Draw(false);
        }

        public void Draw(bool reflecting)
        {

            ICameraService camera = (ICameraService)base.Game.Services.GetService(typeof(ICameraService));
            ITerrainController terrain = (ITerrainController)base.Game.Services.GetService(typeof(ITerrainController));
            IDrawing2DManager drawing = (IDrawing2DManager)base.Game.Services.GetService(typeof(IDrawing2DManager));

            base.GraphicsDevice.RenderState.DepthBufferEnable = true;
            base.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            base.GraphicsDevice.RenderState.AlphaTestEnable = false;

            foreach (IActor currentActor in Actors)
            {
                currentActor.Draw(reflecting, base.GraphicsDevice, camera, terrain, drawing);
            }
        }

        public IActor GetHighlightedActor()
        {
            foreach (IActor currentActor in Actors)
            {
                if (currentActor.IsMouseOver)
                {
                    return currentActor;
                }
            }
            return null;
        }

        public List<IActor> SetSelected()
        {
            _selectedActors.Clear();
            foreach (IActor currentActor in Actors)
            {
                if (currentActor.IsMouseOver)
                {
                    _selectedActors.Add(currentActor);
                    break;
                }
            }
            foreach (IActor currentActor in Actors)
            {
                if (_selectedActors.Contains(currentActor) == false)
                {
                    currentActor.IsSelected = false;
                }
                else
                {
                    currentActor.IsSelected = true;
                }

            }
            return _selectedActors;
        }



        public void Dragging(BoundingFrustum frustum)
        {
            foreach (IActor currentActor in Actors)
            {
                if (frustum.Intersects(currentActor.Sphere))
                {
                    currentActor.IsDragged = true;
                }
                else
                {
                    currentActor.IsDragged = false;
                }
            }

            //float minX, minZ, maxX, maxZ;
            //if (start.X < end.X)
            //{
            //    minX = start.X;
            //    maxX = end.X;
            //}
            //else
            //{
            //    minX = end.X;
            //    maxX = start.X;
            //}

            //if (start.Z < end.Z)
            //{
            //    minZ = start.Z;
            //    maxZ = end.Z;
            //}
            //else
            //{
            //    minZ = end.Z;
            //    maxZ = start.Z;
            //}

            //foreach (IActor currentActor in Actors)
            //{
            //    if (currentActor.Position.X >= minX
            //        && currentActor.Position.X <= maxX
            //        && currentActor.Position.Z >= minZ
            //        && currentActor.Position.Z <= maxZ)
            //    {
            //        currentActor.IsDragged = true;
            //    }
            //    else
            //    {
            //        currentActor.IsDragged = false;
            //    }
            //}
        }

        public void Dragged()
        {
            _selectedActors.Clear();
            foreach (IActor currentActor in Actors)
            {
                if (currentActor.IsDragged)
                {
                    currentActor.IsSelected = true;
                    _selectedActors.Add(currentActor);
                }
                else
                {
                    currentActor.IsSelected = false;
                }
                currentActor.IsDragged = false;
            }
        }

        public void SetDestination(Vector3 coordinates)
        {
            foreach (IActor currentActor in _selectedActors)
            {
                currentActor.SetDestination(coordinates);
            }
        }

        public void SetAttack()
        {
            foreach (IActor currentActor in _selectedActors)
            {
                currentActor.SetAttack(highlightedActor);
            }
        }

    }
}
